﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Model;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Communication.Net.Web
{
    /// <summary>
    /// http请求处理器类(主要是请求处理和会话管理)
    /// </summary>
    public class HttpRequestHandler : IHttpRequestHandler
    {
        /// <summary>
        /// 中间件集合[key:蹭件执行顺序;value:蹭件对象]
        /// </summary>
        private readonly SortedList<int, IMiddleware> _middlewareList = new SortedList<int, IMiddleware>();


        private bool _crossDomain = true;
        /// <summary>
        /// 是否允许跨域[true:允许跨域;false:不允许跨域]
        /// </summary>
        public bool CrossDomain
        {
            get { return _crossDomain; }
            set { _crossDomain = value; }
        }




        /// <summary>
        /// 构造函数
        /// </summary>
        public HttpRequestHandler()
        {

        }



        /// <summary>
        /// 添加中间件
        /// </summary>
        /// <param name="middleware">中间件对象</param>
        /// <param name="order">中间件调用顺序</param>
        public void AddMiddleware(IMiddleware middleware, int order)
        {
            if (middleware == null)
            {
                throw new ArgumentNullException(nameof(middleware));
            }

            this._middlewareList.Add(order, middleware);
        }


        /// <summary>
        /// 处理请求
        /// </summary>
        /// <param name="request">请求</param>
        /// <returns>响应</returns>
        public IHttpResponse ProcessRequest(HttpRequest request)
        {
            if (this._disposed)
            {
                return null;
            }

            IHttpResponse response = null;
            //先验证预判是否支持跨域(只要是api调用,都会先发起跨域预判请求,同比遍历中间件后再验证,先验证效率更高)
            if (string.Equals(request.Method, HttpRequestMethods.OPTIONS, StringComparison.OrdinalIgnoreCase))
            {
                response = new HttpResponse(request.Connection);
                //处理浏览器询问是否允许跨域
                if (this._crossDomain)
                {
                    //允许跨域                     
                    response.StatusCode = HttpStatusCodes.NoContent;
                    response.AddHeader(HttpResponseHeaders.AccessControlAllowMethods, request.Headers[HttpRequestHeaders.AccessControlRequestMethod]);
                    response.AddHeader(HttpResponseHeaders.AccessControlAllowHeaders, request.Headers[HttpRequestHeaders.AccessControlRequestHeaders]);
                }
                else
                {
                    //不允许跨域 
                    response.StatusCode = HttpStatusCodes.Forbidden;
                }

                return response;
            }

            //调用中间件处理
            if (this._middlewareList.Count > 0)
            {
                foreach (var middleware in this._middlewareList.Values)
                {
                    try
                    {
                        if (middleware.TryInvoke(request, out response))
                        {
                            return response;
                        }
                    }
                    catch (Exception ex)
                    {
                        ZLoger.Error(ex);
                    }
                }
            }

            //所有的中间件处理都遍历完后，依然没有调用成功，则说明该http请求是无效的,返回客户端客户端请求的语法错误，服务器无法理解
            response = new HttpResponse(request.Connection);
            response.StatusCode = HttpStatusCodes.NotFound;
            return response;
        }


        /// <summary>
        /// 当前对象是否已释放标识[true:已释放;false:未释放]
        /// </summary>
        private bool _disposed = false;
        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            try
            {
                if (this._disposed)
                {
                    return;
                }
                this._disposed = true;

                foreach (var session in this._middlewareList.Values)
                {
                    session.Dispose();
                }
                this._middlewareList.Clear();
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }
    }
}
